
import os
import filecmp
import json
import tempfile

import ab_ids as ai
import ab_config as ac
import ab_error
import ab_executor
import ab_file
import ab_plugins as ap
import ab_main
import ab_object as ao
import at_main


def _writefile(filename, data):
    with open(filename, 'wb') as f:
        f.write(data)
        f.close()


class Executor:
    def __init__(self, env):
        self.env = env

    def _buildEnvironment(self):
        rootdir = self.env.get('APP_ROOT')
        cf = ac.Config(os.path.join(rootdir, 'config.ini'))
        ab_main.main(rootdir, cf, None, None, no_ui=True)

        self.env.set('ROOT_DIR', rootdir)
        self.env.set('PLUGIN_DIR', cf.readKey(ai.CfgParaPlxPath))
        return cf

    def pluginCategories(self, plugins):
        cat = dict()
        CMAP = {'converter': ap.PlxTpConverter,
                'formatter': ap.PlxTpFormatter,
                'generator': ap.PlxTpGenerator,
                'organizer': ap.PlxTpOrganizer,
                'provider': ap.PlxTpProvider}

        for p in plugins:
            if p.category not in CMAP:
                print 'Error: %s has unknown category %s' % (
                    p.name, p.category)
                continue
            if p.category not in cat:
                cat[CMAP[p.category]] = list()

            cat[CMAP[p.category]].append(self.env.escape(p.name))

        return cat

    def loadPlugin(self, config, loads=None):
        ret = True
        plx = config.readKey(ai.CfgParaPlxObject)

        for pf in loads or list():
            fname = self.env.escape(pf.name)
            ret, names = plx.installFile(fname)
            if ret:
                print ' %s Installed: %s' % (fname, ','.join(names))
            else:
                print ' FAILED: cannot load %s' % fname

        return ret

    def verify(self, result, case, opaque, **kws):
        if case.category == 'converter':
            fd = opaque['formatter'].getFile()

            # because AtrFile supports segements, it's incorrect
            # to compare the full file. use the temporary file.
            temp = tempfile.mktemp('.aof')
            _writefile(temp, fd.read(offset=0))

            if not result.assertTrue(filecmp.cmp(temp, case.target)):
                print ' FAILED: the generated stuff differred from the' \
                      ' target "%s"' % (os.path.realpath(case.target))

            os.unlink(temp)
        elif case.category == 'formatter':
            entry = opaque['tree']
            jso = ao.AtrObject.loadJson(case.target)

            if not result.assertTrue(entry == jso):
                print 'FAILED: the generated tree differred from the target' \
                      ' "%s"' % (os.path.realpath(case.target))
        elif case.category == 'generator':
            if 'outf' not in kws:
                print ' FAILED: no outf defined!'
                result.assertFalse(True)
            elif not result.assertTrue(filecmp.cmp(kws['outf'], case.target)):
                print ' FAILED: the generated file differred from the target' \
                      ' "%s"' % (os.path.realpath(case.target))

    def execute(self, result, case):
        config = self._buildEnvironment()
        ret = self.loadPlugin(config, case.loads)

        def _notify(step, message):
            print 'MSG: [%3d] %s' % (step, message)

        if ret:
            kws = dict()
            app = at_main.App(config)
            executor = ab_executor.Executor(None, app)
            source = ab_file.File(app, case.source, 'rb')
            if case.category == 'generator':
                kws['outf'] = tempfile.mktemp('.aof')
                plxobj = config.readKey(ai.CfgParaPlxObject)
                ret = executor.run(
                    source,
                    no_ui=True,
                    _outf=kws['outf'],
                    plxs={ap.PlxTpGenerator:
                          plxobj.getPlxList(ap.PlxTpGenerator)})
            else:
                ret = executor.run(source, no_ui=True)

            if ret:
                opaque = executor.getResult()
                self.verify(result, case, opaque, **kws)
            else:
                result.assertTrue(False)
                print ' FAILED: executor.run return false'
                error = executor.getError()
                if error is not None:
                    print '-------------------------------'
                    print ab_error.printExcInfo(error)

        return ret
